var HOST = '192.168.0.120';
var PORT = '7001';
var Url = require('url');
var Http = require('http');
var Qs = require('querystring');
var util = require('util');
var thistime = (new Date()).getTime();
//var Mysql = require('./storage/db.js');
var sessions = {};
var http_method_funs = {
    '/who': function(req, res, jsoncallback){
        var user = [];
        for(var i in sessions){
            user.push({uid : sessions[i].uid, nick : sessions[i].nick});
        }
        //console.log(util.inspect(user));
        res.simpleJSON(200, user, jsoncallback);
    },
	'/join' : function(req, res, jsoncallback){
		var uid = Qs.parse(Url.parse(req.url).query).uid;
		var nick = Qs.parse(Url.parse(req.url).query).nick;
		var session = createSession(uid, nick);
		if(session == null){
			res.simpleJSON(200, {error: 'Nick in use'});
			return;
		}
		
        channel.appendMessage(session.uid, 0, "join", "");
		res.simpleJSON(200, {uid : session.uid
							,nick : session.nick
							,starttime : thistime}, jsoncallback);
	},
    '/part' : function(req, res, jsoncallback){
        var uid = Qs.parse(Url.parse(req.url).query).uid;
        var session;
        if (uid && sessions[uid]) {
            session = sessions[uid];
            session.destroy();
        }
        res.simpleJSON(200, {}, jsoncallback);
    },
	'/recv' : function (req, res, jsoncallback) {
		  if (!Qs.parse(Url.parse(req.url).query).since) {
			res.simpleJSON(400, { error: "Must supply since parameter" });
			return;
		  }
		  var uid = Qs.parse(Url.parse(req.url).query).uid;
		  var session;
		  if (uid && sessions[uid]) {
			session = sessions[uid];
			session.poke();
		  }

		  var since = parseInt(Qs.parse(Url.parse(req.url).query).since, 10);

		  channel.query(uid, since, function (messages) {
			if (session) session.poke();
			res.simpleJSON(200, { messages: messages }, jsoncallback);
		  });
		},
	'/send' : function(req, res, jsoncallback){
		var from_uid = Qs.parse(Url.parse(req.url).query).from_uid;
        var to_uid = Qs.parse(Url.parse(req.url).query).to_uid;
		var message = Qs.parse(Url.parse(req.url).query).message;

        /*
		var session = sessions[to_uid];
        if (!session || !message) {
            res.simpleJSON(400, { error: "No such session id" });
            return;
        }
        */
        var session = sessions[from_uid];
        session.poke();
        
        //sendMsgToServer(from_uid, to_uid, message);
        if(to_uid == '0'){
            channel.appendMessage(from_uid, to_uid, "msg", message);
        }else{
            to_uid = to_uid.replace('%2C', ',');
            to_uids = to_uid.split(',');
            for(var i in to_uids){
                channel.appendMessage(from_uid, to_uids[i], "msg", message);
            }
        }
        res.simpleJSON(200, { flag: 1 }, jsoncallback);
	},
    '/callback' : function(req, res, jsoncallback){
        var returns = [];
        for(var i in callbacks){
            returns.push(callbacks[i].uid);
        }
        res.simpleJSON(200, returns, jsoncallback);
    }
}

var Server = Http.createServer(function(req, res){
    req.setEncoding("utf8");
	var handle = Url.parse(req.url).pathname;
	var jsoncallback = Qs.parse(Url.parse(req.url).query).jsoncallback;
	res.simpleJSON = function(code, obj, jsoncallback){
		var body = new Buffer(JSON.stringify(obj));
		body = jsoncallback + "(" + body + ")";
		res.writeHead(code, {'Content-Type' : 'text/json'});
		res.end(body);
	};
	if(typeof http_method_funs[handle] == 'function'){
		http_method_funs[handle](req,res,jsoncallback);
	}else{
		res.simpleJSON(400, {error : 'Not Found!'}, jsoncallback);
		return;
	}
}).listen(PORT, HOST);



function createSession(uid, nick){
	if(nick.length == 0 || nick.length > 40) return null;

	for(var i in sessions){
		var session = sessions[i];
		if(session && sessions[i].uid === uid) return null;
	}

	var session = {
		uid : uid,
		nick : nick,
		timestamp : new Date(),
		poke : function(){
			session.timestamp = new Date()
		},
		destroy : function(){
            channel.appendMessage(session.uid, 0, "part", "");
			delete sessions[session.uid];
		}
	}
	sessions[session.uid] = session;
	return session;
}


var MESSAGE_BACKLOG = 200,
    SESSION_TIMEOUT = 60 * 1000;

var messages = [];
var callbacks = [];
var channel = new function () {
    

  this.appendMessage = function (from_uid, to_uid, type, text) {
    var m = { from_uid : from_uid
            , to_uid: to_uid
            , type: type // "msg", "join", "part"
            , text: text
            , timestamp: (new Date()).getTime()
            };

    switch (type) {
      case "msg":
        //Sys.puts("<" + uid + "> " + text);
        break;
      case "join":
        //Sys.puts(nick + " join");
	    //console.log(from_uid + " join\n");
        break;
      case "part":
        //Sys.puts(nick + " part");
        break;
    }

    messages.push( m );
    //console.log(util.inspect(callbacks, true, null));
    for(var i=0; i<callbacks.length; i++){
        var callback = callbacks[i];
        if(callback.to_uid == to_uid || to_uid == 0 || callback.to_uid == from_uid){
            callback.callback(m);
            //delete callbacks[i];
            //console.log('append ['+type+'] ,to_uid: '+callback.to_uid+'\n');
        }
    }

    while (messages.length > MESSAGE_BACKLOG)
      messages.shift();
  };

  this.query = function (uid, since, callback) {
    var matching = [];
    for (var i = 0; i < messages.length; i++) {
        if(messages[i].to_uid == uid){
            var message = messages[i];
            if (message.timestamp > since){
                matching.push(message);
            }
        }
    }
    
    if (matching.length != 0) {
        callback(matching);
    } else {
        callbacks.push({ timestamp: new Date(), to_uid: uid, callback: callback });
    }
  };

  // clear old callbacks
  // they can hang around for at most 30 seconds.
  setInterval(function () {
    var now = new Date();
    while (callbacks.length > 0 && now - callbacks[0].timestamp > 30*1000) {
      callbacks.shift().callback([]);
    }
  }, 3000);
};
